﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using UCL.Powersource;

namespace PowersourceUIToolkit
{

    /// <summary>
    /// Based on Caliburn.Micro implementation of IoC, filled by bootstrapper
    /// Used by the framework to pull instances from an IoC container and to inject dependencies into certain existing classes.
    /// </summary>
    public sealed class IoC 
    {

        
        static IoC()
        {
        }

        //public static Func<ResourceDictionary> GetResourceDictionary;

        private static IoC _Default;
        public static IoC Default
        {
            get
            {
                return _Default ?? (_Default = new IoC());
            }
            internal set
            {
                _Default = value;
            }

        }

        private Func<Type, string, object> _GetInstance;
        private Func<Type, IEnumerable<object>> _GetAllInstances;
        private Action<object> _BuildUp;
        private Func<Type, Type> _GetDefaultInterfaceImplementationType;
        private Func<IEnumerable<Type>> _GetDefaultInterfaceImplementationTypes;
        
        /// <summary>
        /// Gets an instance by type and key.
        /// </summary>
        public static Func<Type, string, object> GetInstance 
        {
            get { return Default._GetInstance; }
            internal set
            {
                if (null != Default._GetInstance) throw new InvalidOperationException("IoC.GetInstance is already configured.");
                Default._GetInstance = value;
            }
        }

        /// <summary>
        /// Gets all instances of a particular type.
        /// </summary>
        public static Func<Type, IEnumerable<object>> GetAllInstances
        {
            get { return Default._GetAllInstances; }
            internal set
            {
                if (null != Default._GetAllInstances) throw new InvalidOperationException("IoC._GetAllInstances is already configured.");
                Default._GetAllInstances = value;
            }
        }

        public static Func<Type, Type> GetDefaultInterfaceImplementationType
        {
            get { return Default._GetDefaultInterfaceImplementationType; }
            internal set
            {
                if (null != Default._GetDefaultInterfaceImplementationType) throw new InvalidOperationException("IoC._GetDefaultInterfaceImplementationType is already configured.");
                Default._GetDefaultInterfaceImplementationType= value;
            }
        }

        public static Func<IEnumerable<Type>> GetDefaultInterfaceImplementationTypes
        {
            get { return Default._GetDefaultInterfaceImplementationTypes; }
            internal set
            {
                if (null != Default._GetDefaultInterfaceImplementationTypes) throw new InvalidOperationException("IoC._GetDefaultInterfaceImplementationTypes is already configured.");
                Default._GetDefaultInterfaceImplementationTypes = value;
            }
        }

        /// <summary>
        /// Passes an existing instance to the IoC container to enable dependencies to be injected.
        /// </summary>
        public static Action<object> BuildUp
        {
            get { return Default._BuildUp; }
            internal set
            {
                if (null != Default._BuildUp) throw new InvalidOperationException("IoC.BuildUp is already configured.");
                Default._BuildUp = value;
            }
        }
        /// <summary>
        /// Gets an instance by type.
        /// </summary>
        /// <typeparam name="T">The type to resolve from the container.</typeparam>
        /// <returns>The resolved instance.</returns>
        public static T Get<T>()
        {
            return (T)GetInstance(typeof(T), null);
        }

        /// <summary>
        /// Gets an instance from the container using type and key.
        /// </summary>
        /// <typeparam name="T">The type to resolve.</typeparam>
        /// <param name="key">The key to look up.</param>
        /// <returns>The resolved instance.</returns>
        public static T Get<T>(string key)
        {
            return (T)GetInstance(typeof(T), key);
        }


       

        internal void Clear()
        {
            _GetAllInstances = null;
            _GetInstance = null;
            _BuildUp = null;
            _GetDefaultInterfaceImplementationType = null;
            _GetDefaultInterfaceImplementationTypes = null;
        }

        

        
    }
}
